#include "config.h"

#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

// 全局根目录缓冲区：加载配置后会把 root_dir 复制到此处，供其他模块使用。
char g_root_dir[CONFIG_MAX_PATH_LEN] = "";

// 全局 MySQL 配置，供线程池中每个线程在需要时使用以建立独立连接
char g_mysql_host[CONFIG_MAX_HOST_LEN] = "";
int g_mysql_port = 0;
char g_mysql_user[CONFIG_MAX_USER_LEN] = "";
char g_mysql_password[CONFIG_MAX_PASS_LEN] = "";
char g_mysql_db[CONFIG_MAX_DB_LEN] = "";

// 全局系统日志路径（加载配置后填充）
char g_system_log_path[CONFIG_MAX_PATH_LEN] = "";

// 保护对 MySQL 相关全局变量或一次性初始化操作的互斥锁
pthread_mutex_t g_mysql_lock = PTHREAD_MUTEX_INITIALIZER;

// required_field: 表示配置文件中必须包含的字段索引，用于校验是否全部读取到位。
enum required_field
{
    FIELD_SERVER_IP = 0,  // server_ip 是否已读取
    FIELD_SERVER_PORT,    // server_port 是否已读取
    FIELD_ROOT_DIR,       // root_dir 是否已读取
    FIELD_MYSQL_HOST,     // mysql_host 是否已读取
    FIELD_MYSQL_PORT,     // mysql_port 是否已读取
    FIELD_MYSQL_USER,     // mysql_user 是否已读取
    FIELD_MYSQL_PASSWORD, // mysql_password 是否已读取
    FIELD_MYSQL_DB,       // mysql_db 是否已读取
    FIELD_COUNT           // 字段数量
};

static void trim(char *str)
{
    // 去掉字符串两端的空白字符（包括空格、制表符、换行等）
    char *start = str;
    while (*start && isspace((unsigned char)*start))
    {
        start++;
    }

    // end 指向字符串末尾（一个 past-the-end 指针），向前移动到最后一个非空白字符之后
    char *end = start + strlen(start);
    while (end > start && isspace((unsigned char)*(end - 1)))
    {
        end--;
    }

    // 计算去除空白后的长度并移动数据到原始缓冲区起始处
    size_t len = (size_t)(end - start);
    if (start != str && len > 0)
    {
        memmove(str, start, len);
    }
    str[len] = '\0';
}

static system_error_code_t copy_value(char *dest, size_t dest_size, const char *value)
{
    size_t len = strlen(value);
    if (len >= dest_size)
    {
        return SYSTEM_ERR_CONFIG_OVERFLOW;
    }
    memcpy(dest, value, len + 1);
    return SYSTEM_ERR_OK;
}

static system_error_code_t parse_int(const char *value, int *out)
{
    // 使用 strtol 将字符串转换为整数，并验证没有多余字符
    char *end = NULL;
    long parsed = strtol(value, &end, 10);
    // 如果字符串为空或存在非数字尾字符，则视为解析错误
    if (value[0] == '\0' || (end != NULL && *end != '\0'))
    {
        return SYSTEM_ERR_CONFIG_PARSE;
    }
    // 端口号合法范围为 0-65535，超出范围视为解析错误
    if (parsed < 0 || parsed > 65535)
    {
        return SYSTEM_ERR_CONFIG_PARSE;
    }
    *out = (int)parsed;
    return SYSTEM_ERR_OK;
}

system_error_code_t load_server_config(const char *path, server_config_t *cfg)
{
    // 参数校验：path 和 cfg 必须非空
    if (path == NULL || cfg == NULL)
    {
        return SYSTEM_ERR_INVALID_ARGUMENT;
    }

    // 打开配置文件，失败则返回文件错误
    FILE *fp = fopen(path, "r");
    if (fp == NULL)
    {
        return SYSTEM_ERR_CONFIG_FILE;
    }

    // 初始化输出结构体与已读取标记
    memset(cfg, 0, sizeof(*cfg));
    bool seen[FIELD_COUNT] = {false};

    // 逐行读取文件并解析 key=value
    char line[512];
    while (fgets(line, sizeof(line), fp) != NULL)
    {
        // 支持行内或整行注释（# 或 ;），注释后的内容忽略
        char *comment = strpbrk(line, "#;");
        if (comment != NULL)
        {
            *comment = '\0';
        }

        // 去除行首行尾空白，空行跳过
        trim(line);
        if (line[0] == '\0')
        {
            continue;
        }

        // 查找 '=' 分隔符，格式错误即返回解析错误
        char *eq = strchr(line, '=');
        if (eq == NULL)
        {
            fclose(fp);
            return SYSTEM_ERR_CONFIG_PARSE;
        }

        // 分割 key 和 value，并去除各自两端空白
        *eq = '\0';
        char *key = line;
        char *value = eq + 1;
        trim(key);
        trim(value);

        // value 不能为空，否则返回解析错误
        if (value[0] == '\0')
        {
            fclose(fp);
            return SYSTEM_ERR_CONFIG_PARSE;
        }

        // 根据 key 分发并保存到 cfg，相应字段标记为已读取
        system_error_code_t rc = SYSTEM_ERR_OK;
        if (strcmp(key, "server_ip") == 0)
        {
            rc = copy_value(cfg->server_ip, sizeof(cfg->server_ip), value);
            if (rc == SYSTEM_ERR_OK)
            {
                seen[FIELD_SERVER_IP] = true;
            }
        }
        else if (strcmp(key, "server_port") == 0)
        {
            rc = parse_int(value, &cfg->server_port);
            if (rc == SYSTEM_ERR_OK)
            {
                seen[FIELD_SERVER_PORT] = true;
            }
        }
        else if (strcmp(key, "root_dir") == 0)
        {
            rc = copy_value(cfg->root_dir, sizeof(cfg->root_dir), value);
            if (rc == SYSTEM_ERR_OK)
            {
                seen[FIELD_ROOT_DIR] = true;
            }
        }
        else if (strcmp(key, "mysql_host") == 0)
        {
            rc = copy_value(cfg->mysql_host, sizeof(cfg->mysql_host), value);
            if (rc == SYSTEM_ERR_OK)
            {
                seen[FIELD_MYSQL_HOST] = true;
            }
        }
        else if (strcmp(key, "mysql_port") == 0)
        {
            rc = parse_int(value, &cfg->mysql_port);
            if (rc == SYSTEM_ERR_OK)
            {
                seen[FIELD_MYSQL_PORT] = true;
            }
        }
        else if (strcmp(key, "mysql_user") == 0)
        {
            rc = copy_value(cfg->mysql_user, sizeof(cfg->mysql_user), value);
            if (rc == SYSTEM_ERR_OK)
            {
                seen[FIELD_MYSQL_USER] = true;
            }
        }
        else if (strcmp(key, "mysql_password") == 0)
        {
            rc = copy_value(cfg->mysql_password, sizeof(cfg->mysql_password), value);
            if (rc == SYSTEM_ERR_OK)
            {
                seen[FIELD_MYSQL_PASSWORD] = true;
            }
        }
        else if (strcmp(key, "mysql_db") == 0)
        {
            rc = copy_value(cfg->mysql_db, sizeof(cfg->mysql_db), value);
            if (rc == SYSTEM_ERR_OK)
            {
                seen[FIELD_MYSQL_DB] = true;
            }
        }
        else if (strcmp(key, "system_log_path") == 0)
        {
            rc = copy_value(cfg->system_log_path, sizeof(cfg->system_log_path), value);
            if (rc == SYSTEM_ERR_OK)
            {
                // not a required field; don't set any seen[] entry
            }
        }
        else
        {
            // 未知键名忽略以保持向后兼容性
            rc = SYSTEM_ERR_OK;
        }

        // 如果在保存或解析过程中发生错误（例如溢出或数值错误），关闭文件并返回对应错误码
        if (rc != SYSTEM_ERR_OK)
        {
            fclose(fp);
            return rc;
        }
    }

    // 关闭文件描述符
    fclose(fp);

    // 检查是否读取到所有必需字段
    for (size_t i = 0; i < FIELD_COUNT; ++i)
    {
        if (!seen[i])
        {
            return SYSTEM_ERR_CONFIG_MISSING;
        }
    }

    // 将 root_dir 复制到全局缓冲区，供其他模块使用
    system_error_code_t root_rc = copy_value(g_root_dir, sizeof(g_root_dir), cfg->root_dir);

    if (root_rc != SYSTEM_ERR_OK)
    {
        return root_rc;
    }

    // 复制 MySQL 配置到全局变量，供线程池中使用。
    // 使用互斥锁保护写入，避免与可能的并发读取冲突。
    pthread_mutex_lock(&g_mysql_lock);
    copy_value(g_mysql_host, sizeof(g_mysql_host), cfg->mysql_host);
    g_mysql_port = cfg->mysql_port;
    copy_value(g_mysql_user, sizeof(g_mysql_user), cfg->mysql_user);
    copy_value(g_mysql_password, sizeof(g_mysql_password), cfg->mysql_password);
    copy_value(g_mysql_db, sizeof(g_mysql_db), cfg->mysql_db);
    // 复制系统日志路径到全局缓冲区（可为空）
    // 仅在配置文件中提供该字段时才覆盖全局值，避免用空字符串覆盖已有默认
    if (cfg->system_log_path[0] != '\0') {
        copy_value(g_system_log_path, sizeof(g_system_log_path), cfg->system_log_path);
    }
    pthread_mutex_unlock(&g_mysql_lock);

    // 成功
    return SYSTEM_ERR_OK;
}
